
//
// 120526 - AH - Created.
//

package org.soekrat.engine.socraton;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;

import org.soekrat.environment.Orb;

/**
 * <p>
 *   Utility methods for resolving a 
 *   {@link Bison}.
 * </p>
 * @author Arne Halvorsen (AH)
 * @author Laetitia Le Chatton (LLC)
 */
public final class ResolveBisonDataOLD
{
  private ResolveBisonDataOLD(){} // Utility pattern dictates private constructor.
  
  /**
   * <p>
   *   Result of resolving a
   *   {@link Bison}.
   * </p>
   * @author Arne Halvorsen (AH)
   * @author Laetitia Le Chatton (LLC)
   */
  public static final class BisonValue
  {
    private final String m_mime;
    
    private final URL m_url;
    
    private final Object m_value;
    
    private final String m_attrName;
    
    /**
     * <p>
     *   Constructor.
     * </p>
     * @param v Value bison has been resolved to.
     */
    private BisonValue(Object v)
    { 
      m_mime=null; 
      m_url=null; 
      m_value=v; 
      m_attrName=(v==null) ? null : "bisons:"+v.getClass().getName();
    }
    
    /**
     * <p>
     *   Constructor.
     * </p>
     * @param mime MIME type of data bison has been resolved to.
     * @param url  URL to resource. 
     * @param v    Value bison has been resolved to.
     */
    private BisonValue(String mime, URL url, Object v)
    {
      m_mime=null;
      m_url=url;
      m_value=v;
      m_attrName=(v==null) ? null : "bisons:"+v.getClass().getName();
    }
    
    /**
     * <p>
     *   Gets mime type.
     * </p>
     * @return Mime type, {@code null} if does not apply.
     */
    public String getMime(){ return m_mime; }
    
    /**
     * <p>
     *   Gets URL to resource.
     * </p>
     * @return URL or {@code null} if does not apply.
     */
    public URL url(){ return m_url; }
    
    /**
     * <p>
     *   Gets value bison has been resolved to.
     * </p>
     * @return Value.
     */
    public Object getValue(){ return m_value; }
    
    /**
     * <p>
     *   Gets attribute name value should be indexed under.
     * </p>
     * @return Name.
     */
    public String getAttrName(){ return m_attrName; }
    
  }
  
  /**
   * <p>
   *   Resolves a
   *   {@link Bison} and put resolved values on
   *   {@link Orb}.
   * </p>
   * @param orb   {@link Orb}.
   * @param bison {@link Bison} to resolve.
   */
  public static void resolve(Orb orb, Bison bison)
  {
    if (orb==null)
    {
      throw new NullPointerException("orb");
    }
    if (bison==null)
    {
      throw new NullPointerException("bison");
    }
    
    BisonValue bv=resolve(bison);
    Object value=bv.getValue();
    if (value!=null)
    {
      String attrName=bv.getAttrName();
      @SuppressWarnings("unchecked")
      List<Object> l=(List<Object>)orb.getAttribute(attrName);
      if (l==null)
      {
        l=new ArrayList<Object>();
        orb.setAttribute(attrName, l);
      }
      l.add(value);
    }
  }
  
  /**
   * <p>
   *   Resolves a 
   *   {@link Bison}.
   * </p>
   * @param bison {@link Bison} to resolve.
   * @return Result.
   */
  public static BisonValue resolve(Bison bison)
  {
    if (bison==null)
    {
      throw new NullPointerException("bison");
    }
    
    String data=bison.getLocation();
   
    if (data.startsWith("mime:"))
    {
      int idx=data.indexOf("http:/");
      if (idx==-1) return new BisonValue(data);
      String mime=data.substring(5, idx);
      String urls=data.substring(idx);
      if (mime.length()>0 && urls.length()>0)
      {
        try
        {
          URL url=new URL(urls);
          Object value=fetch(url, mime);
          return new BisonValue(mime, url, value);
        }
        catch (MalformedURLException mx)
        {
          return new BisonValue(data);
        }
      }
      else
      {
        return new BisonValue(data);
      }
    }
    else if (data.startsWith("http:/"))
    {
      try
      {
        URL url=new URL(data);
        String mime=getMimeFromSpec(data);
        Object value=fetch(url, mime);
        return new BisonValue(mime, url, value);
      }
      catch (MalformedURLException mx)
      {
        return new BisonValue(data);
      }
    }
    else if (data.startsWith("class:"))
    {
      String cname=data.substring(6);
      if (cname.length()>=0)
      {
        try
        {
          Class<?> clazz=Class.forName(cname);
          Object value=clazz.newInstance();
          return new BisonValue(value);
        }
        catch (Exception x)
        {
          return new BisonValue(data);
        }
      }
    }
    
    return new BisonValue(data);
  }
  
  /**
   * <p>
   *   Maps 'extensions' to mime types.
   * </p>
   */
  private static final Map<String, String> c_ext=new HashMap<String, String>();
  
  /**
   * <p>
   *   Gets MIME type given 'extension' maps to.
   * </p>
   * @param s Extension.
   * @return MIME type or {@code null} if non found.
   */
  private static String getMimeFromSpec(String s)
  {
    int idx=s.lastIndexOf(".");
    if (idx==-1) return null;
    String ext=s.substring(idx+1);
    return ext.length()>0 ? c_ext.get(ext) : null;
  }
  
  /**
   * <p>
   *   Interface for object that fetches resources from the net.
   * </p>
   * @author Arne Halvorsen (AH)
   * @author Laetitia Le Chatton (LLC)
   */
  private static interface Fetcher
  {
    /**
     * <p>
     *   MIME types {@code this} know how to fetch.
     * </p>
     * @return Types.
     */
    String[] getMimeTypes();
    
    /**
     * <p>
     *   Fetches.
     * </p>
     * @param url URL for resource to fetch.
     * @return Fetched or {@code null} if could not.
     */
    Object fetch(URL url);
    
  };
  
  /**
   * <p>
   *   {@link Fetcher} that fetches images.
   * </p>
   * @author Arne Halvorsen (AH)
   */
  private static final class ImageFetcher implements Fetcher
  {
    private final String[] m_mtypes={ "image/jpg", "image/gif", "image/png" };

    // Specified in Fetcher.
    public String[] getMimeTypes(){ return m_mtypes; }

    // Specified in Fetcher.
    public Object fetch(URL url)
    {
      try
      {
        BufferedImage image=ImageIO.read(url);
        return image;
      }
      catch (IOException iox)
      {
        return null;
      }
    }
   
  }
  
  /**
   * <p>
   *   {@link Fetcher}s indexed by MIMME types they fetch.
   * </p>
   */
  private static Map<String, Fetcher> c_fetchers=new HashMap<String, Fetcher>();
  
  /**
   * <p>
   *   Registers
   *   {@link Fetcher}.
   * </p>
   * @param f {@code Fetcher} to register.
   */
  private static void addFetcher(Fetcher f)
  {
    String[] mt=f.getMimeTypes();
    for (String t : mt) c_fetchers.put(t, f);
  }
  
  /**
   * <p>
   *   Fetch object from the net.
   * </p>
   * @param url  URL to resource.
   * @param mime MIME type.
   * @return     Fetched or {@code null} if could not be fetched.
   */
  private static Object fetch(URL url, String mime)
  {
    if (mime==null) return null;
    Fetcher fetcher=c_fetchers.get(mime);
    return fetcher==null ? null : fetcher.fetch(url);
  }
  
  /**
   * <p>
   *   Initialized mapping from extensions to MIME types and registers
   *   {@code Fetcher}s.
   * </p>
   */
  static
  {
    c_ext.put("jpg", "image/jpg");
    c_ext.put("gif", "image/gif");
    c_ext.put("png", "image/png");
    
    addFetcher(new ImageFetcher());
  }
  
}
